package org.opens.util;

import cn.hutool.core.lang.UUID;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

/**
 * 功能描述
 *
 * @author by zhangyuming
 * @date 2022/11/4
 */
@Slf4j
public class FileUtil2 {

    private static final String TEMP_DIR = System.getProperty("java.io.tmpdir");

    /**
     * 从指定文件 fileName 的 numberOfReadStartLines 开始读取  numberOfReadLines 行数据.
     *
     * @param fileName               文件名
     * @param numberOfReadStartLines 读取起始行
     * @param numberOfReadLines      读取行数
     * @return 读取到的数据
     * @throws FileNotFoundException 读取的文件不存在抛出的异常
     */
    public static List<String> readLine(String fileName, Integer numberOfReadStartLines, Integer numberOfReadLines) throws FileNotFoundException {
        File file = new File(fileName);

        if (!file.exists()) {
            throw new FileNotFoundException("文件" + fileName + "不存在!");
        }

        if (numberOfReadLines == null || numberOfReadLines <= 0) {
            throw new IllegalArgumentException("读取行数必须大于0");
        }

        if (numberOfReadStartLines == null || numberOfReadStartLines <= 0) {
            throw new IllegalArgumentException("读取开始行数必须大于0");
        }

        int fileLineNumber = readFileLineNumber(fileName);
        if (numberOfReadStartLines > fileLineNumber) {
            throw new IllegalArgumentException("读取文件起始行数必须小于文件总行数(" +  fileLineNumber + ")");
        }

        List<String> result = new ArrayList<>();

        try (
                FileInputStream fileInputStream = new FileInputStream(file);
                InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8);
                BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        ) {
            int lineNumber = 0;
            int readLineCount = 0;
            String line = null;
            while ((line = bufferedReader.readLine()) != null) {
                lineNumber++;

                // 如果当前行码小于读取起始行数, 则跳过当前行
                if (lineNumber < numberOfReadStartLines) {
                    continue;
                }

                // 如果已经读取的行数超过了设置的行数, 则立即退出
                if (readLineCount >= numberOfReadLines) {
                    break;
                }

                result.add(line);
                readLineCount++;
            }
        } catch (Exception e) {
            // pass
            e.printStackTrace();
        }

        return result;
    }

    /**
     * 读取文件行数
     * @param fileName 文件名
     * @return 文件行数
     * @throws FileNotFoundException 文件不存在时抛出此异常
     */
    public static int readFileLineNumber(String fileName) throws FileNotFoundException {
        File file = new File(fileName);
        if (!file.exists()) {
            throw new FileNotFoundException("文件" + fileName + "不存在!");
        }

        int lineNumber = 0;
        try (
                FileReader fileReader = new FileReader(file);
                LineNumberReader lineNumberReader = new LineNumberReader(fileReader);
        ) {
            // 使文件指针跳转到末尾
            lineNumberReader.skip(Long.MAX_VALUE);
            lineNumber = lineNumberReader.getLineNumber() + 1;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return lineNumber;
    }

    /**
     * 阶段式读取文件, 并进行回调
     * @param filename 读取的文件
     * @param stageNumber 每阶段读取的行数
     * @param skipNumber 跳过行数
     * @param fileLinesConsumer 回调函数
     * @throws FileNotFoundException 读取的文件不存在的时候抛出此异常
     */
    public static void stageReadFile(String filename, int stageNumber, int skipNumber, Consumer<List<String>> fileLinesConsumer) throws FileNotFoundException {
        int lineNumber = readFileLineNumber(filename);

        if (lineNumber < stageNumber) {
            throw new IllegalArgumentException("阶段读取行数必须小于等于文件总行数(" + lineNumber + ")!");
        }

        // 是否第一次读取
        boolean firstRead = true;

        for (int i = 1; i <= lineNumber;) {
            List<String> lines = readLine(filename, i + (firstRead ? skipNumber : 0), stageNumber);

            if (fileLinesConsumer != null) {
                fileLinesConsumer.accept(lines);
            }

            i += stageNumber;
            if (firstRead) {
                i += skipNumber;
            }

            firstRead = false;
        }
    }

    /**
     * 自动生成并创建临时目录
     */
    public static String generateTemporaryDirectory() {
        String genDir = TEMP_DIR + File.separator + UUID.fastUUID();
        File tempDirectory = new File(genDir);
        if (!tempDirectory.exists()) {
            boolean created = tempDirectory.mkdirs();
            if (!created) {
                throw new RuntimeException("目录[ " + genDir + " ]创建失败！");
            }
        }

        return tempDirectory.getAbsolutePath();
    }

    public static void deleteFileOrDirectory(File fileOrDir) {
        if (!fileOrDir.exists()) {
            // System.out.println("File or directory does not exist: " + path);
            return;
        }

        if (fileOrDir.isDirectory()) {
            deleteDirectory(fileOrDir);
        } else {
            if (!fileOrDir.delete()) {
                System.out.println("Failed to delete file: " + fileOrDir.getAbsolutePath());
                log.error("文件 {} 删除失败！", fileOrDir.getAbsolutePath());
            }
        }
    }

    /**
     * 递归删除指定目录下的所有文件 或者 直接删除指定文件
     * @param path  待删除的目录或文件
     */
    public static void deleteFileOrDirectory(String path) {
        deleteFileOrDirectory(new File(path));
    }

    private static void deleteDirectory(File directory) {
        File[] files = directory.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    deleteDirectory(file);
                } else {
                    if (!file.delete()) {
                        // System.out.println("Failed to delete file: " + file.getAbsolutePath());
                        log.error("文件 {} 删除失败！", file.getAbsolutePath());
                    }
                }
            }
        }
        if (!directory.delete()) {
            // System.out.println("Failed to delete directory: " + directory.getAbsolutePath());
            log.error("文件 {} 删除失败！", directory.getAbsolutePath());
        }
    }

}
